using System;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using HslCommunication.BasicFramework;

namespace HslCommunication.Core.Net
{
	/// <summary>
	/// 基于Udp的应答式通信类<br />
	/// Udp - based responsive communication class
	/// </summary>
	public class NetworkUdpBase : NetworkBase
	{
		private SimpleHybirdLock hybirdLock = null;

		private int connectErrorCount = 0;

		/// <inheritdoc cref="P:HslCommunication.Core.Net.NetworkDoubleBase.IpAddress" />
		public virtual string IpAddress
		{
			get;
			set;
		}

		/// <inheritdoc cref="P:HslCommunication.Core.Net.NetworkDoubleBase.Port" />
		public virtual int Port
		{
			get;
			set;
		}

		/// <inheritdoc cref="P:HslCommunication.Core.Net.NetworkDoubleBase.ReceiveTimeOut" />
		public int ReceiveTimeout
		{
			get;
			set;
		}

		/// <inheritdoc cref="P:HslCommunication.Core.Net.NetworkDoubleBase.ConnectionId" />
		public string ConnectionId
		{
			get;
			set;
		}

		/// <summary>
		/// 获取或设置一次接收时的数据长度，默认2KB数据长度，特殊情况的时候需要调整<br />
		/// Gets or sets the length of data received at a time. The default length is 2KB
		/// </summary>
		public int ReceiveCacheLength
		{
			get;
			set;
		} = 2048;


		/// <summary>
		/// 实例化一个默认的方法<br />
		/// Instantiate a default method
		/// </summary>
		public NetworkUdpBase()
		{
			hybirdLock = new SimpleHybirdLock();
			ReceiveTimeout = 5000;
			ConnectionId = SoftBasic.GetUniqueStringByGuidAndRandom();
		}

		/// <summary>
		/// 核心的数据交互读取，发数据发送到串口上去，然后从串口上接收返回的数据<br />
		/// The core data is read interactively, the data is sent to the serial port, and the returned data is received from the serial port
		/// </summary>
		/// <param name="value">完整的报文内容</param>
		/// <returns>是否成功的结果对象</returns>
		public virtual OperateResult<byte[]> ReadFromCoreServer(byte[] value)
		{
			if (!Authorization.nzugaydgwadawdibbas())
			{
				return new OperateResult<byte[]>(StringResources.Language.AuthorizationFailed);
			}
			base.LogNet?.WriteDebug(ToString(), StringResources.Language.Send + " : " + SoftBasic.ByteToHexString(value));
			hybirdLock.Enter();
			try
			{
				IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(IpAddress), Port);
				Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
				socket.SendTo(value, value.Length, SocketFlags.None, remoteEP);
				if (ReceiveTimeout < 0)
				{
					hybirdLock.Leave();
					return OperateResult.CreateSuccessResult(new byte[0]);
				}
				socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout);
				IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Any, 0);
				EndPoint remoteEP2 = iPEndPoint;
				byte[] array = new byte[ReceiveCacheLength];
				int count = socket.ReceiveFrom(array, ref remoteEP2);
				byte[] array2 = array.Take(count).ToArray();
				hybirdLock.Leave();
				base.LogNet?.WriteDebug(ToString(), StringResources.Language.Receive + " : " + SoftBasic.ByteToHexString(array2));
				connectErrorCount = 0;
				return OperateResult.CreateSuccessResult(array2);
			}
			catch (Exception ex)
			{
				hybirdLock.Leave();
				if (connectErrorCount < 100000000)
				{
					connectErrorCount++;
				}
				return new OperateResult<byte[]>(-connectErrorCount, ex.Message);
			}
		}

		/// <inheritdoc cref="M:HslCommunication.Core.Net.NetworkDoubleBase.IpAddressPing" />
		public IPStatus IpAddressPing()
		{
			Ping ping = new Ping();
			return ping.Send(IpAddress).Status;
		}

		/// <inheritdoc />
		public override string ToString()
		{
			return $"NetworkUdpBase[{IpAddress}:{Port}]";
		}
	}
}
